package tech.waterism.utils;

import cn.hutool.core.date.DatePattern;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.SerializationUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import tech.waterism.constant.StatisticsConstants;
import tech.waterism.constant.StringConstants;
import tech.waterism.dto.*;
import tech.waterism.entity.FMCaliparascope;
import tech.waterism.entity.FMParameter;
import tech.waterism.entity.ModelTypeSpecify;
import tech.waterism.exception.CustomException;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Component
public class ModelPlatformUtils {
    private final String DIMENSION_SEPERATER = ";";

    /**
     * 等号形式的参数列表转为参数map
     *
     * @param arcd -- 只做异常信息输出
     * @param mdcd -- 只做异常信息输出
     */
    private Map<String, String> generateRequestDataMap(List<String> calList, Map<String, ModelTypeSpecify> typeMap,
                                                       String arcd, String mdcd) throws Exception {
        Map<String, String> result = new HashMap<>();
        for (String item : calList) {
            String[] arr = item.trim().split("=");
            if (arr.length < 2) {
                JSONObject data = new JSONObject();
                data.put("arcd", arcd);
                data.put("mdcd", mdcd);
                data.put("isError", true);
                String msg = "没有配置参数值: " + (arr[0] != null ? arr[0] : null);
                data.put("msg", msg);
                throw new CustomException(arcd + " " + mdcd + " 没有配置参数值: " + (arr[0] != null ? arr[0] : null),
                        data);
            }
            ModelTypeSpecify type = typeMap.get(arr[0].trim());
            if (type != null) {
                result.put(arr[0].trim(), generateValueWithType(arr[1], type.getSValue()));
            } else {
                result.put(arr[0].trim(), generateValue(arr[1]));
            }
        }
        return result;
    }

    private String generateValue(String parameter) {
        String[] valuesDimension = parameter.split("//")[0].trim().split(DIMENSION_SEPERATER);
        if (valuesDimension.length == 1) {
            String[] values = parameter.split("//")[0].trim().split("\\s+");
            String value = null;
            if (values.length == 1) {
                if (values[0].startsWith(".")) {
                    values[0] = "0" + values[0];
                }
                value = values[0];
            } else if (values.length > 1) {
                for (int i = 0; i < values.length; i++) {
                    if (values[i].startsWith(".")) {
                        values[i] = "0" + values[i];
                    }
                }
                value = Arrays.asList(values).toString();
            }
            return value;
        } else if (valuesDimension.length > 1) {
            List<List<Double>> valueList = new LinkedList<>();
            for (String s : valuesDimension) {
                List<Double> value = new LinkedList<>();
                String[] values = s.trim().split("\\s+");
                for (int i = 0; i < values.length; i++) {
                    if (values[i].startsWith(".")) {
                        values[i] = "0" + values[i];
                    }
                    value.add(Double.parseDouble(values[i]));
                }
                valueList.add(value);
            }
            return JSON.toJSONString(valueList);
        } else {
            return null;
        }
    }

    private String generateValueWithType(String parameter, String type) {
        String[] values = parameter.split("//")[0].trim().split("\\s+");
        String value = null;
        if (type.equalsIgnoreCase(StringConstants.ARRAY)) {
            for (int i = 0; i < values.length; i++) {
                if (values[i].startsWith(".")) {
                    values[i] = "0" + values[i];
                }
            }
            value = Arrays.asList(values).toString();
        } else if (type.equalsIgnoreCase(StringConstants.INT)) {
            int i = 0;
            if (values[i].startsWith(".")) {
                values[i] = "0";
            } else {
                values[i] = values[i].split("\\.")[0];
            }
            value = values[i];
        } else {
            value = values[0];
        }
        return value;
    }

    /**
     * 二维数组转置
     */
    private Double[][] transpose(Double[][] arr) {
        Double[][] result = new Double[arr[0].length][arr.length];
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                result[j][i] = arr[i][j];
            }
        }
        return result;
    }

    /**
     * 二维数组转置
     */
    private List<List<Double>> transpose(List<List<Double>> arr) {
        int size = 0;
        for (int i = 0; i < arr.size(); i++) {
            List<Double> item = arr.get(i);
            if (item.size() > size) {
                size = item.size();
            }
        }
        Double[][] input = new Double[arr.size()][size];
        for (int i = 0; i < arr.size(); i++) {
            List<Double> item = arr.get(i);
            for (int j = 0; j < item.size(); j++) {
                input[i][j] = item.get(j);
            }
        }
        Double[][] tempResult = transpose(input);
        List<List<Double>> result = new ArrayList<>();
        for (Double[] doubles : tempResult) {
            result.add(Arrays.asList(doubles));
        }
        return result;
    }

    public void callModelForecast(ModelTestDto dto, List<ForecastDataDto> data, Integer clen, String unt, Date symdh,
                                  Date fymdh, String arcd, String artp, Boolean testModel) throws Exception {
        callModelForecast(dto, data, clen, unt, symdh, fymdh, arcd, artp, testModel, null);
    }

    public void callModelForecast(ModelTestDto dto, List<ForecastDataDto> data, Integer clen, String unt, Date symdh,
                                  Date fymdh, String arcd, String artp, Boolean testModel, List<FStWeightDto> stWeight) throws Exception {
        callModelForecast(dto, data, clen, unt, symdh, fymdh, arcd, artp, testModel, stWeight, false);
    }

    /**
     * 调用模型平台
     *
     * @param data      当前使用数据
     * @param testModel 是否试算模式
     */
    public void callModelForecast(ModelTestDto dto, List<ForecastDataDto> data, Integer clen, String unt, Date symdh,
                                  Date fymdh, String arcd, String artp, Boolean testModel, List<FStWeightDto> stWeight,
                                  boolean returnEndStatus) throws Exception {
        Map<String, String> requestData = new HashMap<>();
        Map<String, Integer> statusMap = new HashMap<>();
        String mdcd = dto.getMdcd();
        generateRequstData(requestData, statusMap, mdcd, dto, arcd);
        //
        List<String> dt = new LinkedList<>();
        List<Double> rain = new LinkedList<>();
        List<Double> q = new LinkedList<>();
        List<Double> runoffSim = new LinkedList<>();
        Double[][] rSim = new Double[data.size()][];
        int statusIndex = 0;
        int statusEndIndex = 0;
        if (returnEndStatus) {
            statusEndIndex = data.size() - 1;
        }
        for (int i = 0; i < data.size(); i++) {
            ForecastDataDto forecastDataDto = data.get(i);
            Date tempDt = forecastDataDto.getDt();
            if (tempDt != null) {
                if (tempDt.equals(symdh)) {
                    statusIndex = i;
                }
                SimpleDateFormat sf = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
                dt.add(sf.format(tempDt));
            }
            if (testModel) {
                rain.add(forecastDataDto.getRain());
                q.add(forecastDataDto.getQ());
                if (dto.getRunoffSim() != null) {
                    runoffSim.add(dto.getRunoffSim());
                }
                if (dto.getRSim() != null) {
                    rSim[i] = dto.getRSim();
                }
            } else {
                if (artp.equalsIgnoreCase(StringConstants.AREA_ARTP)) {
                    if (forecastDataDto.getRain() != null) {
                        rain.add(forecastDataDto.getRain());
                    } else {
                        JSONObject err = new JSONObject();
                        err.put("arcd", arcd);
                        throw new CustomException("请检查(" + arcd + ")单元数据完整性", err);
                    }
                } else {
                    if (forecastDataDto.getQ() != null) {
                        q.add(forecastDataDto.getQ());
                    } else {
                        JSONObject err = new JSONObject();
                        err.put("arcd", arcd);
                        throw new CustomException("请检查(" + arcd + ")单元数据完整性", err);
                    }
                }
                if (forecastDataDto.getRunoffSim() != null) {
                    runoffSim.add(forecastDataDto.getRunoffSim());
                }
                if (forecastDataDto.getRSim() != null) {
                    rSim[i] = forecastDataDto.getRSim();
                }
            }
        }
        requestData.put("dt", JSON.toJSONString(dt));
        SimpleDateFormat sf = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
        requestData.put("start", JSON.toJSONString(sf.format(symdh)));
        requestData.put("rain", JSON.toJSONString(rain));
        requestData.put("q", JSON.toJSONString(q));
        requestData.put("runoffSim", JSON.toJSONString(runoffSim));
        if (rSim[0] != null && rSim[0].length > 0 && rSim[0][0] != null) {
            Double[][] rSimT = transpose(rSim);
            requestData.put("rSim", JSON.toJSONString(rSimT));
        }
        //
        requestData.put("clen", JSON.toJSONString(clen));
        ModelExecuteCustomDto executeCustomDto = new ModelExecuteCustomDto();
        if (unt != null && unt.equals("M")) {
            mdcd = mdcd + "_min";
        }
        executeCustomDto.setModelName(mdcd);
        List<String> dataStrings = new ArrayList<>();
        dataStrings.add(JSON.toJSONString(requestData));
        executeCustomDto.setParaData(dataStrings);
        List<String> paralists = new LinkedList<>();
        paralists.add(JSON.toJSONString(Map.class));
        executeCustomDto.setParaList(paralists);
        log.debug("arcd: " + arcd);
        // log.debug("executeCustomDto: " + JSON.toJSONString(executeCustomDto));
        ApiResult<PredictResultDto> apiResult = modelFeignClient.predictCustom(executeCustomDto);
        if (apiResult.getCode() == 0) {
            // log.debug(apiResult.getData().getPredictResult().toString());
            PredictResult predictResult = apiResult.getData().getPredictResult();
            try {
                for (int i = 0; i < data.size(); i++) {
                    ForecastDataDto resultData = data.get(i);
                    if (predictResult.getDt() != null) {
                        resultData.setDt(predictResult.getDt()[i]);
                    }
                    if (predictResult.getQ() != null) {
                        resultData.setQ(predictResult.getQ()[i]);
                    }
                    if (predictResult.getQSim() != null) {
                        resultData.setQSim(predictResult.getQSim()[i]);
                    }
                    if (predictResult.getZ() != null) {
                        resultData.setZ(predictResult.getZ()[i]);
                    }
                    if (predictResult.getZSim() != null) {
                        resultData.setZSim(predictResult.getZSim()[i]);
                    }
                    if (predictResult.getRain() != null) {
                        resultData.setRain(predictResult.getRain()[i]);
                    }
                    if (predictResult.getRunoffSim() != null) {
                        resultData.setRunoffSim(predictResult.getRunoffSim()[i]);
                    }
                    if (predictResult.getRSim() != null && predictResult.getRSim().length > 0) {
                        double[][] temp = predictResult.getRSim();
                        Double[] tempRSim = new Double[temp.length];
                        for (int j = 0; j < tempRSim.length; j++) {
                            if (temp[j] != null) {
                                tempRSim[j] = temp[j][i];
                            }
                        }
                        resultData.setRSim(tempRSim);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                log.error("executeCustomDto: " + JSON.toJSONString(executeCustomDto));
                log.error("apiResult:" + apiResult.getData().getPredictResult().toString());
                throw new Exception("模型调用失败：单元名称：" + arcd + "，模型名称：" + executeCustomDto.getModelName());
            }
            Map<String, List<String>> newStatus = predictResult.getNewStatus();
            String numberPattern = "0.000";
            DecimalFormat df = new DecimalFormat(numberPattern);
            if (newStatus != null && dto.getStatuses() != null && dto.getStatuses().size() > 0) {
                List<FMStatusDto> statusDtos = dto.getStatuses();
                ModelTestDto dtoCopy = SerializationUtils.clone(dto);
                List<FMStatusDto> statusDtosEnd = dtoCopy.getStatuses();
                for (String key : newStatus.keySet()) {
                    Integer index = statusMap.get(key);
                    if (index != null) {
                        StringBuilder stringBuilder = new StringBuilder();
                        stringBuilder.append(key);
                        stringBuilder.append("=");
                        String statusString = statusDtos.get(index).getStatus();
                        String dataPart = statusString.trim().split("//")[0];
                        // status for symdh
                        String newStatusString = newStatus.get(key).get(statusIndex);
                        if (newStatusString.startsWith("[")) {
                            String[] arr = JSON.parseObject(newStatusString, String[].class);
                            if (arr.length == 0) {
                                continue;
                            }
                            String oriStatus = dataPart.trim().split("=")[1].trim();
                            Pattern pattern = Pattern.compile("\\s+");
                            Matcher matcher = pattern.matcher(oriStatus);
                            String seperator = " ";
                            if (matcher.find()) {
                                seperator = matcher.group(0);
                            }
                            String[] formatArr = new String[arr.length];
                            for (int i = 0; i < arr.length; i++) {
                                if (arr[i].contains(".")) {
                                    formatArr[i] = df.format(Double.parseDouble(arr[i]));
                                } else {
                                    formatArr[i] = arr[i];
                                }
                            }
                            stringBuilder.append(String.join(seperator, formatArr));
                        } else {
                            String status = newStatusString;
                            if (newStatusString.contains(".")) {
                                status = df.format(Double.parseDouble(newStatusString));
                            }
                            stringBuilder.append(status);
                        }
                        Pattern pattern1 = Pattern.compile("//");
                        Matcher matcher1 = pattern1.matcher(statusDtos.get(index).getStatus().trim());
                        if (matcher1.find()) {
                            stringBuilder.append(" ");
                            stringBuilder.append(statusString.substring(matcher1.start()).trim());
                        }
                        statusDtos.get(index).setStatus(stringBuilder.toString());
                        // status for eymdh
                        if (returnEndStatus) {
                            StringBuilder stringBuilderEnd = new StringBuilder();
                            stringBuilderEnd.append(key);
                            stringBuilderEnd.append("=");
                            String newStatusStringE = newStatus.get(key).get(statusEndIndex);
                            if (newStatusStringE.startsWith("[")) {
                                String[] arr = JSON.parseObject(newStatusStringE, String[].class);
                                if (arr.length == 0) {
                                    continue;
                                }
                                String oriStatus = dataPart.trim().split("=")[1].trim();
                                Pattern pattern = Pattern.compile("\\s+");
                                Matcher matcher = pattern.matcher(oriStatus);
                                String seperator = " ";
                                if (matcher.find()) {
                                    seperator = matcher.group(0);
                                }
                                String[] formatArr = new String[arr.length];
                                for (int i = 0; i < arr.length; i++) {
                                    if (arr[i].contains(".")) {
                                        formatArr[i] = df.format(Double.parseDouble(arr[i]));
                                    } else {
                                        formatArr[i] = arr[i];
                                    }
                                }
                                stringBuilderEnd.append(String.join(seperator, formatArr));
                            } else {
                                String status = newStatusStringE;
                                if (newStatusStringE.contains(".")) {
                                    status = df.format(Double.parseDouble(newStatusStringE));
                                }
                                stringBuilderEnd.append(status);
                            }
                            Pattern patternE = Pattern.compile("//");
                            Matcher matcherE = patternE.matcher(statusDtos.get(index).getStatus().trim());
                            if (matcherE.find()) {
                                stringBuilderEnd.append(" ");
                                stringBuilderEnd.append(statusString.substring(matcherE.start()).trim());
                            }
                            statusDtosEnd.get(index).setStatus(stringBuilderEnd.toString());
                        }
                    }
                }
                if (returnEndStatus) {
                    dto.setStatusesEnd(statusDtosEnd);
                }
            }
        } else {
            log.error("模型平台错误信息：" + apiResult.getMsg());
            log.error("请求数据：" + JSON.toJSONString(executeCustomDto));
            throw new Exception("模型平台请求错误，错误信息：" + apiResult.getMsg() + "，单元名称：" + arcd + "，模型名称：" +
                    executeCustomDto.getModelName());
        }
    }

    /**
     * 整理parameter和status，变成请求map
     */
    public void generateRequstData(Map<String, String> requestData, Map<String, Integer> statusMap, String mdcd,
                                   ModelTestDto dto, String arcd) throws Exception {
        Map<String, ModelTypeSpecify> typeMap = modelTypeSpecifyMapper.selectList(
                        new LambdaQueryWrapper<ModelTypeSpecify>().eq(ModelTypeSpecify::getModel, mdcd)
                                .eq(ModelTypeSpecify::getSType, StatisticsConstants.MODEL_TYPE_MAP)).stream()
                .collect(Collectors.toMap(ModelTypeSpecify::getSKey, v -> v));
        List<FMStatusDto> statusDtos = dto.getStatuses();
        if (statusDtos != null && statusDtos.size() > 0) {
            List<String> statusList = new LinkedList<>();
            for (int i = 0; i < statusDtos.size(); i++) {
                FMStatusDto fmStatusDto = statusDtos.get(i);
                if (fmStatusDto.getNorow() % 2 == 0) {
                    statusList.add(fmStatusDto.getStatus());
                    if (statusMap != null) {
                        statusMap.put(fmStatusDto.getStatus().trim().split("=")[0].trim(), i);
                    }
                }
            }
            Map<String, String> requetMap = generateRequestDataMap(statusList, typeMap, arcd, mdcd);
            requestData.putAll(requetMap);
        }
        //
        List<FMParameter> fmParameters = dto.getParameters();
        if (fmParameters != null && fmParameters.size() > 0) {
            generateParameters(fmParameters, requestData, mdcd);
        }
    }

    /**
     * 整理parameters参数，移除参数数值前后的多余信息
     */
    private void generateParameters(List<FMParameter> fmParameters, Map<String, String> requestData, String mdcd)
            throws Exception {
        List<ModelTypeSpecify> typeList = modelTypeSpecifyMapper.selectList(
                new LambdaQueryWrapper<ModelTypeSpecify>().eq(ModelTypeSpecify::getModel, mdcd)
                        .eq(ModelTypeSpecify::getSType, StatisticsConstants.MODEL_TYPE_PARATABLE));
        if (typeList.size() > 0) {
            generateValueByTypeList(typeList, fmParameters, requestData, mdcd);
        } else {
            List<String> paramList = fmParameters.stream().filter(i -> i.getNorow() > 3).map(FMParameter::getParameter)
                    .collect(Collectors.toList());
            paramList = paramList.subList(0, paramList.size() - 1);
            Map<String, ModelTypeSpecify> typeMap = modelTypeSpecifyMapper.selectList(
                            new LambdaQueryWrapper<ModelTypeSpecify>().eq(ModelTypeSpecify::getModel, mdcd)
                                    .eq(ModelTypeSpecify::getSType, StatisticsConstants.MODEL_TYPE_MAP)).stream()
                    .collect(Collectors.toMap(ModelTypeSpecify::getSKey, v -> v));
            Map<String, String> requetMap =
                    generateRequestDataMap(paramList, typeMap, fmParameters.get(0).getArcd(), mdcd);
            requestData.putAll(requetMap);
        }
    }

    private void generateValueByTypeList(List<ModelTypeSpecify> typeList, List<FMParameter> fmParameters,
                                         Map<String, String> requestData, String mdcd) throws Exception {

        for (ModelTypeSpecify item : typeList) {
            switch (item.getSValue()) {
                case StringConstants.SINGLE:
                    FMParameter parameter = fmParameters.stream().filter(i -> i.getNorow().equals(item.getNorow()))
                            .collect(Collectors.toList()).get(0);
                    String value = generateValue(parameter.getParameter());
                    requestData.put(item.getSKey(), value);
                    break;
                case StringConstants.RANGE:
                    List<String> strategies = Arrays.asList(item.getStrategy().split(StringConstants.COMMA));
                    Stream<String> parameterList;
                    List<List<Double>> valueList;
                    if (strategies.contains("toEnd")) {
                        parameterList = fmParameters.stream().filter(i -> (i.getNorow() >= item.getNorow()))
                                .map(FMParameter::getParameter);
                    } else {
                        break;
                    }
                    if (strategies.contains("removeFirstOne")) {
                        valueList = parameterList.map(i -> {
                            String[] values = i.trim().split("\\s+");
                            return Arrays.asList(values).subList(1, values.length).stream().map(Double::parseDouble)
                                    .collect(Collectors.toList());
                        }).collect(Collectors.toList());
                    } else {
                        valueList = parameterList.map(i -> {
                            String[] values = i.trim().split("\\s+");
                            return Arrays.stream(values).map(Double::parseDouble).collect(Collectors.toList());
                        }).collect(Collectors.toList());
                    }
                    if (strategies.contains("transpose")) {
                        valueList = transpose(valueList);
                    }
                    requestData.put(item.getSKey(), JSON.toJSONString(valueList));
                    break;
                case StringConstants.SELECT_RANGE:
                    String[] strategyArr = item.getStrategy().split(StringConstants.COMMA);
                    String groupNum = fmParameters.stream().filter(i -> i.getNorow().equals(item.getNorow()))
                            .collect(Collectors.toList()).get(0).getParameter().split("//")[0].trim();
                    List<FMParameter> fmParameterList = fmParameters.stream().filter(i -> (i.getNorow() >=
                                    Integer.parseInt(strategyArr[0]) +
                                            (Integer.parseInt(groupNum) - 1) * Integer.parseInt(strategyArr[1])))
                            .filter(i -> (i.getNorow() < Integer.parseInt(strategyArr[0]) +
                                    Integer.parseInt(groupNum) * Integer.parseInt(strategyArr[1])))
                            .collect(Collectors.toList());
                    String[] keys = item.getSKey().split(StringConstants.COMMA);
                    if (fmParameterList.size() != keys.length) {
                        throw new Exception("配置项错误，请检查 " + mdcd);
                    }
                    for (int i = 0; i < keys.length; i++) {
                        requestData.put(keys[i], generateValue(fmParameterList.get(i).getParameter()));
                    }
                    break;
                default:
                    break;
            }
        }
    }

    // moea
    public void callModelCalibrateMoea(FMIndexDto fmIndexDto, double[] valueList, String[] typeList,
                                       List<ForecastDataDto> data, Integer clen, String unt, String arnm, String artp) throws Exception {
        callModelCalibrateMoea(fmIndexDto, valueList, typeList, data, clen, unt, arnm, artp, false);
    }

    // moea
    public void callModelCalibrateMoea(FMIndexDto fmIndexDto, double[] valueList, String[] typeList,
                                       List<ForecastDataDto> data, Integer clen, String unt, String arnm, String artp, boolean returnEndStatus)
            throws Exception {
        if (valueList.length == 0) {
            ModelTestDto modelTestDto = new ModelTestDto();
            BeanUtils.copyProperties(fmIndexDto, modelTestDto);
            callModelForecast(modelTestDto, data, clen, unt, data.get(0).getDt(), null, arnm, artp, false, null,
                    returnEndStatus);
            return;
        }
        // fmIndexDto.setParameters(null);
        Map<String, String> requestData = new HashMap<>();
        String mdcd = fmIndexDto.getMdcd();
        // set param
        Map<String, ModelTypeSpecify> typeMap = modelTypeSpecifyMapper.selectList(
                        new LambdaQueryWrapper<ModelTypeSpecify>().eq(ModelTypeSpecify::getModel, mdcd)
                                .eq(ModelTypeSpecify::getSType, StatisticsConstants.MODEL_TYPE_MAP)).stream()
                .collect(Collectors.toMap(ModelTypeSpecify::getSKey, v -> v));
        for (int i = 0; i < fmIndexDto.getCaliParascopes().size(); i++) {
            FMCaliparascope caliParascope = fmIndexDto.getCaliParascopes().get(i);
            if (typeList[i].equals(StringConstants.INT)) {
                requestData.put(caliParascope.getParam(), JSON.toJSONString((int) valueList[i]));
            } else {
                requestData.put(caliParascope.getParam(), JSON.toJSONString(valueList[i]));
            }
        }
        List<FMParameterDto> extraParameters = fmIndexDto.getExtraParameters();
        if (extraParameters != null && extraParameters.size() > 0) {
            List<String> paramList =
                    extraParameters.stream().map(FMParameter::getParameter).collect(Collectors.toList());
            Map<String, String> requetMap = generateRequestDataMap(paramList, typeMap, arnm, fmIndexDto.getMdcd());
            requestData.putAll(requetMap);
        }
        Map<String, Integer> statusMap = new HashMap<>();
        List<FMStatusDto> statusDtos = fmIndexDto.getStatuses();
        if (statusDtos != null && statusDtos.size() > 0) {
            List<String> statusList = new LinkedList<>();
            for (int i = 0; i < statusDtos.size(); i++) {
                FMStatusDto fmStatusDto = statusDtos.get(i);
                if (fmStatusDto.getNorow() % 2 == 0) {
                    statusList.add(fmStatusDto.getStatus());
                    statusMap.put(fmStatusDto.getStatus().trim().split("=")[0].trim(), i);
                }
            }
            Map<String, String> requetMap = generateRequestDataMap(statusList, typeMap, null, fmIndexDto.getMdcd());
            requestData.putAll(requetMap);
        }
        // set data
        List<String> dt = new LinkedList<>();
        List<Double> rain = new LinkedList<>();
        List<Double> q = new LinkedList<>();
        List<Double> runoffSim = new LinkedList<>();
        Double[][] rSim = new Double[data.size()][];
        for (int i = 0; i < data.size(); i++) {
            ForecastDataDto forecastDataDto = data.get(i);
            Date tempDt = forecastDataDto.getDt();
            if (tempDt != null) {
                SimpleDateFormat sf = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
                dt.add(sf.format(tempDt));
            }
            if (artp.equalsIgnoreCase(StringConstants.AREA_ARTP)) {
                if (forecastDataDto.getRain() != null) {
                    rain.add(forecastDataDto.getRain());
                } else {
                    rain.add(0.0);
                }
            } else {
                if (forecastDataDto.getQ() != null) {
                    q.add(forecastDataDto.getQ());
                } else {
                    q.add(0.0);
                }
            }
            if (forecastDataDto.getRunoffSim() != null) {
                runoffSim.add(forecastDataDto.getRunoffSim());
            }
            if (forecastDataDto.getRSim() != null) {
                rSim[i] = forecastDataDto.getRSim();
            }
        }
        requestData.put("dt", JSON.toJSONString(dt));
        SimpleDateFormat sf = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
        Date symdh = data.get(0).getDt();
        requestData.put("start", JSON.toJSONString(sf.format(symdh)));
        requestData.put("rain", JSON.toJSONString(rain));
        requestData.put("q", JSON.toJSONString(q));
        requestData.put("runoffSim", JSON.toJSONString(runoffSim));
        if (rSim[0] != null && rSim[0][0] != null) {
            Double[][] rSimT = transpose(rSim);
            requestData.put("rSim", JSON.toJSONString(rSimT));
        }
        int statusEndIndex = 0;
        if (returnEndStatus) {
            statusEndIndex = data.size() - 1;
        }
        //
        requestData.put("clen", JSON.toJSONString(clen));
        ModelExecuteCustomDto executeCustomDto = new ModelExecuteCustomDto();
        if (unt != null && unt.equals("M")) {
            mdcd = mdcd + "_min";
        }
        executeCustomDto.setModelName(mdcd);
        List<String> dataStrings = new ArrayList<>();
        dataStrings.add(JSON.toJSONString(requestData));
        executeCustomDto.setParaData(dataStrings);
        List<String> paralists = new LinkedList<>();
        paralists.add(JSON.toJSONString(Map.class));
        executeCustomDto.setParaList(paralists);
        // log.debug(JSON.toJSONString(executeCustomDto));
        ApiResult<PredictResultDto> apiResult = modelFeignClient.predictCustom(executeCustomDto);
        if (apiResult.getCode() == 0) {
            // log.debug(apiResult.getData().getPredictResult().toString());
            PredictResult predictResult = apiResult.getData().getPredictResult();
            for (int i = 0; i < data.size(); i++) {
                ForecastDataDto resultData = data.get(i);
                if (predictResult.getDt() != null) {
                    resultData.setDt(predictResult.getDt()[i]);
                }
                if (predictResult.getQ() != null) {
                    resultData.setQ(predictResult.getQ()[i]);
                }
                if (predictResult.getQSim() != null) {
                    resultData.setQSim(predictResult.getQSim()[i]);
                }
                if (predictResult.getZ() != null) {
                    resultData.setZ(predictResult.getZ()[i]);
                }
                if (predictResult.getZSim() != null) {
                    resultData.setZSim(predictResult.getZSim()[i]);
                }
                if (predictResult.getRain() != null) {
                    resultData.setRain(predictResult.getRain()[i]);
                }
                if (predictResult.getRunoffSim() != null) {
                    resultData.setRunoffSim(predictResult.getRunoffSim()[i]);
                }
                if (predictResult.getRSim() != null && predictResult.getRSim().length > 0) {
                    double[][] temp = predictResult.getRSim();
                    Double[] tempRSim = new Double[temp.length];
                    for (int j = 0; j < tempRSim.length; j++) {
                        if (temp[j] != null) {
                            tempRSim[j] = temp[j][i];
                        }
                    }
                    resultData.setRSim(tempRSim);
                }
                // update status
                Map<String, List<String>> newStatus = predictResult.getNewStatus();
                String numberPattern = "0.000";
                DecimalFormat df = new DecimalFormat(numberPattern);
                if (newStatus != null && fmIndexDto.getStatuses() != null && fmIndexDto.getStatuses().size() > 0 &&
                        returnEndStatus) {
                    FMIndexDto dtoCopy = SerializationUtils.clone(fmIndexDto);
                    List<FMStatusDto> statusDtosEnd = dtoCopy.getStatuses();
                    for (String key : newStatus.keySet()) {
                        Integer index = statusMap.get(key);
                        if (index != null) {
                            StringBuilder stringBuilder = new StringBuilder();
                            stringBuilder.append(key);
                            stringBuilder.append("=");
                            String statusString = statusDtos.get(index).getStatus();
                            String dataPart = statusString.trim().split("//")[0];
                            // status for eymdh
                            String newStatusStringE = newStatus.get(key).get(statusEndIndex);
                            if (newStatusStringE.startsWith("[")) {
                                String[] arr = JSON.parseObject(newStatusStringE, String[].class);
                                if (arr.length == 0) {
                                    continue;
                                }
                                String oriStatus = dataPart.trim().split("=")[1].trim();
                                Pattern pattern = Pattern.compile("\\s+");
                                Matcher matcher = pattern.matcher(oriStatus);
                                String seperator = " ";
                                if (matcher.find()) {
                                    seperator = matcher.group(0);
                                }
                                String[] formatArr = new String[arr.length];
                                for (int ii = 0; ii < arr.length; ii++) {
                                    if (arr[ii].contains(".")) {
                                        formatArr[ii] = df.format(Double.parseDouble(arr[ii]));
                                    } else {
                                        formatArr[ii] = arr[ii];
                                    }
                                }
                                stringBuilder.append(String.join(seperator, formatArr));
                            } else {
                                String status = newStatusStringE;
                                if (newStatusStringE.contains(".")) {
                                    status = df.format(Double.parseDouble(newStatusStringE));
                                }
                                stringBuilder.append(status);
                            }
                            Pattern patternE = Pattern.compile("//");
                            Matcher matcherE = patternE.matcher(statusDtos.get(index).getStatus().trim());
                            if (matcherE.find()) {
                                stringBuilder.append(" ");
                                stringBuilder.append(statusString.substring(matcherE.start()).trim());
                            }
                            statusDtosEnd.get(index).setStatus(stringBuilder.toString());
                        }
                    }
                    fmIndexDto.setStatusesEnd(statusDtosEnd);
                }
            }
        } else {
            log.error("模型平台错误信息：" + apiResult.getMsg());
            log.error("请求数据：" + JSON.toJSONString(executeCustomDto));
            throw new Exception("模型平台请求错误，错误信息：" + apiResult.getMsg() + "，单元名称：" + arnm + "，模型名称：" +
                    executeCustomDto.getModelName());
        }
    }
}
